﻿using System;

using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Ujimanet.ISO_IEC_18004_2000
{
    public interface IQR { 
    
    }
   public enum ErrorCorrectionLevel { L = 1, M = 2, Q = 3, H = 4 }
 
    public class QR
    {
        #region Number of Bits in Character Count Indicator
        #region Numeric Mode Character Count
        public int NumericModeCharacterCount
        {
            get {
                if (((int)_version) <= 9) {
                    return  10;
                }
                else if (((int)_version) > 9 && ((int)_version) <= 26) {
                    return  12;
                }
                else {
                    return  14;
                }
            }
        }
        #endregion
        #region Alphanumeric Mode Character Count
        public int AlphanumericModeCharacterCount
        {
            get
            {
                if (((int)_version) <= 9)
                {
                    return 9;
                }
                else if (((int)_version) > 9 && ((int)_version) <= 26)
                {
                    return 11;
                }
                else
                {
                    return 13;
                }
            }
        }
        #endregion
        #region EightBitByte Mode Character Count
        public int EightBitByteModeCharacterCount
        {
            get
            {
                if (((int)_version) <= 9)
                {
                    return 8;
                }
                else if (((int)_version) > 9 && ((int)_version) <= 26)
                {
                    return 16;
                }
                else
                {
                    return 16;
                }
            }
        }
        #endregion
        #region Kanji Mode Character Count
        public int KanjiModeCharacterCount
        {
            get
            {
                if (((int)_version) <= 9)
                {
                    return 8;
                }
                else if (((int)_version) > 9 && ((int)_version) <= 26)
                {
                    return 10;
                }
                else
                {
                    return 12;
                }
            }
        }
        #endregion
        #endregion
        private int _moduleCount;
        private string _data;
        private int _codewordCount;
        private int _maskPattern;
        private ArrayList _modules;
        
        

        public ArrayList Modules
        {
            get { return _modules; }
            
        }

        public void insertModule(QRModule module) {
            if (_modules == null)
                _modules = new ArrayList();
            _modules.Add(module);
        }
        public int MaskPattern
        {
            get { return _maskPattern; }
            set { _maskPattern = value; }
            
        }
        public int CodewordCount
        {
            get { return _codewordCount; }
           
        }
        private ErrorCorrectionLevel _errorCorrectionLevel;

        public ErrorCorrectionLevel ErrorCorrectionLevel
        {
            get { return _errorCorrectionLevel; }
            set { _errorCorrectionLevel = value; }
        }
        private ArrayList _codewords;

        public ArrayList Codewords
        {
            get { return _codewords; }
            set { _codewords = value; }
        }
        private ArrayList _bytes;

        public ArrayList Bytes
        {
            get { 

                ArrayList ArrList_bytes = new ArrayList();

                foreach (string s in _codewords)
                {
                    string first, second, total;
                    first = String.Format("{0:X}", Convert.ToInt64(s.Substring(0, 4), 2));
                    second = String.Format("{0:X}", Convert.ToInt64(s.Substring(4, 4), 2));
                    total = Convert.ToInt64(first + second, 16).ToString();

                    byte b = byte.Parse(total);


                    ArrList_bytes.Add(b);


                }



                byte[] inData = (byte[])ArrList_bytes.ToArray(new byte().GetType());
                byte[] outData;

                // ReedSol calculation
                ReedSol rs = new ReedSol();

                rs.rs_init_gf(0x12d);
                rs.rs_init_code(10, 16);
                rs.rs_encode(16, inData, out  outData);

                ArrayList output_al = new ArrayList();

                foreach (byte b in outData)
                {
                    ArrList_bytes.Add(b);


                }
                return ArrList_bytes;
            }
            
        }

        private ArrayList setData(string data){
            int blockCount = 0;
            ArrayList list = new ArrayList();
            StringBuilder tempSB = new StringBuilder();

            foreach (char c in data)
            {
                tempSB.Append(c);
                if (++blockCount == 3)
                {
                    list.Add(tempSB.ToString());
                    tempSB = new StringBuilder();
                    blockCount = 0;
                }
            }
            if (tempSB.Length > 0)
                list.Add(tempSB.ToString());
            ArrayList binaryList = new ArrayList();
            foreach (string s in list)
            {
                StringBuilder sb = new StringBuilder();
                switch (s.Length)
                {
                    case 3: binaryList.Add(String.Format("{0:0000000000}", int.Parse(Convert.ToString(int.Parse(s), 2))));
                        break;
                    case 2:
                        binaryList.Add(String.Format("{0:0000000}", int.Parse(Convert.ToString(int.Parse(s), 2))));
                        break;
                    case 1:
                        binaryList.Add(String.Format("{0:0000}", int.Parse(Convert.ToString(int.Parse(s), 2))));
                        break;
                }



            }

            binaryList.Insert(0, String.Format("{0:0000000000}", int.Parse(Convert.ToString(int.Parse(data.Length.ToString()), 2))));
            binaryList.Add("0000");


            binaryList.Insert(0, String.Format("{0:0000}", int.Parse(Convert.ToString(1, 2))));
            StringBuilder strB_bStream = new StringBuilder();

            foreach (string codeword in binaryList)
            {
                strB_bStream.Append(codeword);
            }
            ArrayList codeWords = new ArrayList();
            int charIndex = 0;
            StringBuilder sb_codeWord = new StringBuilder();

            foreach (char c in strB_bStream.ToString())
            {
                sb_codeWord.Append(c);
                charIndex++;
                if (charIndex == 8)
                {
                    charIndex = 0;
                    codeWords.Add(sb_codeWord.ToString());
                    sb_codeWord = new StringBuilder();
                }

            }
            if (sb_codeWord.Length != 0)
            {
                while (sb_codeWord.Length < 8)
                {
                    sb_codeWord.Append('0');
                }
                codeWords.Add(sb_codeWord.ToString());
            }
            int altCount = 0;
            _codewordCount = codeWords.Count;
            while (codeWords.Count < 16)
            {
                if (++altCount % 2 == 0)
                {
                    codeWords.Add("00010001");
                }
                else
                {
                    codeWords.Add("11101100");
                }

            }
            return codeWords;
        }
        public string Data
        {
            get { return _data; }
            set { _codewords = setData( value);
            _data = value;
            
            
            }
        }

        public int ModuleCount
        {
            get { return _moduleCount; }
            set { _moduleCount = value; }
        }
        private QRVersion _version = QRVersion.Version1;
        public QRVersion Version
        {
            get { return _version; }
            set { _version = value; }
        }
        private EncodingType _encodingType;
        public EncodingType EncodingType
        {
            get { return _encodingType; }
            set { _encodingType = value; }
        }

    }
    #region ModeIndicators
    enum ModeIndicator
    {
        Terminator, Numeric, Alphanumeric, StructuredAppend, _8BitByte, FNC1_1, ECI = 7, Kanji, FNC1_2
    }
    #endregion
    #region EncodingTypes
    public enum EncodingType
    {
        NotDef,
        Ascii,
        C40,
        Text,
        X12,
        Edifact,
        Binary
    }
    #endregion
    #region QRVersions
    public enum QRVersion
    {
        Version1 = 21,
        Version2 = 25,
        Version3 = 29,
        Version4 = 33,
        Version5 = 37,
        Version6 = 41,
        Version7 = 45,
        Version8 = 49,
        Version9 = 53,
        Version10 = 57,
        Version11 = 61,
        Version12 = 65,
        Version13 = 69,
        Version14 = 73,
        Version15 = 77,
        Version16 = 81,
        Version17 = 85,
        Version18 = 89,
        Version19 = 93,
        Version20 = 97,
        Version21 = 101,
        Version22 = 105,
        Version23 = 109,
        Version24 = 113,
        Version25 = 117,
        Version26 = 121,
        Version27 = 125,
        Version28 = 129,
        Version29 = 133,
        Version30 = 137,
        Version31 = 141,
        Version32 = 145,
        Version33 = 149,
        Version34 = 153,
        Version35 = 157,
        Version36 = 161,
        Version37 = 165,
        Version38 = 169,
        Version39 = 173,
        Version40 = 177
    }
    #endregion
    public class QRModule {
        private Point _point;
        private bool _value;

        public bool Value
        {
            get { return _value; }
            set { _value = value; }
        }

        public Point Point
        {
            get { return _point; }
            set { _point = value; }
        }
        public QRModule(Point p,bool value) {
            _point = p;
            _value = value;
        }
        public QRModule(Point p)
        {
            _point = p;
            _value = true ;
        }

    }
}
